#pragma once

#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <cstdlib>
#include <time.h>
#include <unistd.h>

template <class T>
class RingQueue
{
private:
    // 循环队列
    std::vector<T> _ringQueue;
    // 最大容量
    int _max_size;
    // 互斥锁
    // 防止多线程的时候生产者一直生产,直到满了，死锁；消费者一直消费，直到空了，死锁
    pthread_mutex_t _p_mtx;
    pthread_mutex_t _c_mtx;
    // 条件变量---实现同步
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
    // 记录在循环队列中，生产者消费者的下标
    int _c_step;
    int _p_step;
    // 生产者消费者的信号量
    sem_t _c_sem;
    sem_t _p_sem;

public:
    RingQueue(int max_size)
        : _ringQueue(max_size), _max_size(max_size), _c_step(0), _p_step(0)
    {
        pthread_mutex_init(&_p_mtx, nullptr);
        pthread_mutex_init(&_c_mtx, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        sem_init(&_c_sem, 0, 0);
        sem_init(&_p_sem, 0, _max_size);
    }
    // 出队 ---  消费者消费
    void rqPop(T *out)
    {
        // 如果信号量不为0， 减减；为0，则被阻塞，直到信号量大于0
        sem_wait(&_c_sem);
        // 对共享资源进行操作---> 将数据从循环队列中删除
        pthread_mutex_lock(&_c_mtx);

        *out = _ringQueue[_c_step];
        _c_step++;
        _c_step %= _max_size;

        pthread_mutex_unlock(&_c_mtx);
        sem_post(&_p_sem);
    }
    void rqEqueue(const T& in)
    {
        sem_wait(&_p_sem);
        pthread_mutex_lock(&_p_mtx);

        _ringQueue[_p_step] = in;
        _p_step++;
        _p_step %= _max_size;

        pthread_mutex_unlock(&_p_mtx);
        sem_post(&_c_sem);
    }
    ~RingQueue() 
    {
        pthread_mutex_destroy(&_p_mtx);
        pthread_mutex_destroy(&_c_mtx);

        sem_destroy(&_c_sem);
        sem_destroy(&_p_sem);
    }
};